<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>选择日期与时间</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <style>
        body{margin:0;padding:0;outline: 0;font-family: serif;}
        /* 日期选择器 */
        .date_picker{width:252px;margin:20px auto;font-family:arial;position: relative;border-radius: 6px;border: 0 solid transparent;box-shadow: 0 2px 20px rgba(0,0,0,0.1);}
        .date_picker .calendar{width:100%;background-color: #fff;display: flex;flex-direction: column;}
        .calendar .calendar_datetime{display: flex;justify-content: space-around;padding: 4px 0;margin: 16px 16px 0;border:1px solid #e5e5e5;border-radius:5px;}
        .calendar_datetime .date_val{width:120px;font-size:18px;text-align: center;}
        .calendar_datetime .time_val{width:60px;font-size:18px;text-align: center;padding-left: 10px;border-left:1px solid #e5e5e5;}
        .calendar_datetime .calendar_time{display:none;position: absolute;will-change: top,left;top:45px;left: 152px;background-color: #fff;box-shadow: 0 2px 20px rgba(0,0,0,0.1);}
        .calendar_datetime #timeList{list-style: none;height:230px;overflow-y: scroll;padding:3px;margin:0;}
        .calendar_datetime #timeList li{cursor: pointer;padding: 8px 12px;line-height: 20px;vertical-align: middle;list-style: none;font-size: 14px;transition: all 0.3s ease-in-out;}
        .calendar_datetime #timeList li:hover{background-color:#e5e5e5;}
        .calendar_datetime .active_time{background-color:#e5e5e5;}

        .calendar .calendar_tle{text-align:center;padding:0 16px;margin-top: 8px;}
        .calendar_tle #yearMonth{display: inline-block;width: 130px;padding: 5px 0;}
        .calendar_tle .prev:before {content: "<";}
        .calendar_tle .next:before {content: ">";}
        .calendar_tle .prev,.next{display: inline-block;width:36px;line-height:32px;font-size: 22px;cursor: pointer;}

        .calendar .calendar_body{padding-bottom: 16px;}
        .calendar_body .date_list{list-style: none;display: flex;margin: 0 7px;padding: 0;}
        .calendar_body .date_list ul{width:100%;padding-left:0;margin:0;font-weight:bold;font-size:14px;}
        .calendar_body .date_list ul li{display:inline-block;list-style:none;width:32px;line-height:32px;margin: 1px;text-align:center;box-sizing:border-box;border-radius: 3px;}
        .calendar_body #days li:hover{background:#ccc;cursor: pointer}
        .calendar_body .before_day{color:#a8a8a8;}
        .calendar_body .to_day{color:#6ac13c;background-color: #e9f8df;}
        .calendar_body .after_day{color:#565656;}
        .calendar_body .active_day{background-color: #1b9aee;color: #f7f7f7;pointer-events:none;cursor:not-allowed;box-shadow:none;}

        .calendar .calendar_btn{display:flex;justify-content:space-between;padding: 0 16px 16px;}
        .calendar_btn .clear_date,.sure_date{flex:1;padding:6px 20px;outline: 0;border-radius: 5px;cursor: pointer;transition: all 0.3s ease;}
        .calendar_btn .clear_date{background-color:#fff;color:#1b9aee;border:1px solid #ccecff;}
        .calendar_btn .sure_date{margin-left: 16px;background-color:#1b9aee;color:#fff;border:0 solid transparent}
        .calendar_btn .clear_date:hover{background-color:#f2fbff;}
        .calendar_btn .sure_date:hover{background-color:#0171c2;}
        .calendar_body .empty{display:inline-block;width:34px}
    </style>
</head>
<body>
<div class="date_picker">
    <div class="calendar">
        <div class="calendar_datetime">
            <div class="date_val" id="dateVal"></div>
            <div class="time_val" id="timeVal">09:00</div>
            <div class="calendar_time">
                <ul id="timeList"></ul>
            </div>
        </div>
        <div class="calendar_tle">
            <span class="prev" id="prev"></span>
            <span id="yearMonth"></span>
            <span class="next" id="next"></span>
        </div>
        <div class="calendar_body">
            <div class="date_list">
                <ul>
                    <li>一</li><li>二</li><li>三</li><li>四</li><li>五</li><li>六</li><li>日</li>
                </ul>
            </div>
            <div class="date_list">
                <ul id="days"></ul>
            </div>
        </div>
        <div class="calendar_btn">
            <button class="clear_date">清除</button>
            <button class="sure_date">确定</button>
        </div>
    </div>
</div>
</body>
<script>
    const toDay = new Date();
    let currentYear = toDay.getFullYear();
    let currentMonth = toDay.getMonth(); // 数组索引
    const currentDay = toDay.getDate();
    const toDate = getDate(currentYear, currentMonth, currentDay);
    // 生成日历 yyyy-mm-dd
    function getDate(year, month, day) {
        const selectedDate = new Date(year, month, day);
        return `${selectedDate.getFullYear()}-${String(selectedDate.getMonth() + 1).padStart(2, '0')}-${String(selectedDate.getDate()).padStart(2, '0')}`;
    }
    // // 闰年计算规则 能被4整除但不能被100整除，或者能被400整除
    function generateCalendar(year, month){
        const daysInMonth = new Date(year, month + 1, 0).getDate(); // 当前是几号
        const firstDay = new Date(year, month, 1).getDay();         // 当前是周几
        const calendarDays = [];
        // 生成空白占位
        if (firstDay === 0) {
            calendarDays.push(Array(6).fill(`<span class='empty'></span>`).join(''));
        } else if (firstDay > 0 && firstDay <= 7) {
            calendarDays.push(Array(firstDay - 1).fill(`<span class='empty'></span>`).join(''));
        }
        const selectedDay = $('#dateVal').text();
        for(let day = 1; day <= daysInMonth; day++){
            const curDate = getDate(currentYear, currentMonth, day);
            const isBefore = curDate < toDate;
            const isToday = curDate === toDate;
            const isAfter = curDate > toDate;
            const isSelected = curDate === selectedDay;
            // 当天之前 当天 当天之后
            const setClass = [
                isBefore ? 'before_day' : '',
                isToday ? 'to_day' : '',
                isAfter ? 'after_day' : '',
                isSelected ? 'active_day' : '',
            ].filter(c => c).join(' ');
            calendarDays.push(`<li class='${setClass}' data-date='${curDate}' >${day}</li>`);
        }
        return calendarDays.join('');
    }
    function updateCalendar() {
        const daysHtml = generateCalendar(currentYear, currentMonth);
        $('#days').html(daysHtml);
        $('#yearMonth').text(`${currentYear}年 ${currentMonth + 1}月`);
    }
    $('#prev').click(function() {
        currentMonth--;
        if(currentMonth < 0){
            currentYear--;
            currentMonth = 11;
        }
        updateCalendar();
    });
    $('#next').click(function() {
        currentMonth++;
        if(currentMonth > 11){
            currentYear++;
            currentMonth = 0;
        }
        updateCalendar();
    });
    function selectDate(element) {
        const selectedDay = $(element).text();
        const formattedDate = getDate(currentYear, currentMonth, selectedDay);
        $('#dateVal').text(formattedDate);
        $('#days li').removeClass('active_day');
        $(element).addClass('active_day');
        $(".calendar_time").slideUp(300);
    }
    // 手动选择 时间
    $('#days').on('click', 'li', function() {
        selectDate(this)
    });
    // 3、优化时间列表生成
    let isupdown = true; 
    function generateTimeSlots() {
        return Array.from({length: 24}, (_, h) => 
            ['00', '15', '30', '45'].map(m => 
            `<li>${String(h).padStart(2, '0')}:${m}</li>`
            ).join('')
        ).join('');
    }
    $("#timeList").html(generateTimeSlots());
    // 列表 选择时间
    $("#timeList").on('click','li',function () {
        $(this).siblings().removeClass("active_time");
        $(this).addClass("active_time");
        $("#timeVal").text($(this).text());
        $(".calendar_time").slideUp(300);
        isupdown = true;
    });
    // 列表显示与隐藏
    $("#timeVal").on('click',function () {
        if(isupdown){
            $(".calendar_time").fadeIn(500);
            isupdown = false;
        }else{
            $(".calendar_time").slideUp(300);
            isupdown = true;
        }
    });
    $("#dateVal").text(getDate(currentYear, currentMonth, currentDay));
    updateCalendar();
</script>
</html>